using System;
using libsvm;

/* Conversion notes (Andrew Poh):
 * Support Class removed.
 * BinaryWriter.Write() replaced with Write().
 * Removed nested construction of StreamReader.
 */
namespace libsvm
{

	public class svm_predict
	{
		public static double atof(System.String s)
		{
			return System.Double.Parse(s);
		}
	
		public static int atoi(System.String s)
		{
			try
			{
				return System.Int32.Parse(s);
			}catch(Exception)
			{
				int ia = 1;
			}

			return 0;
		}
	
		public void predict(System.IO.StreamReader input, System.IO.BinaryWriter output, svm_model model, int predict_probability)
		{
			int correct = 0;
			int total = 0;
			double error = 0;
			double sumv = 0, sumy = 0, sumvv = 0, sumyy = 0, sumvy = 0;
		
			int svm_type = svm.svm_get_svm_type(model);
			int nr_class = svm.svm_get_nr_class(model);
			int[] labels = new int[nr_class];
			double[] prob_estimates = null;
		
			if (predict_probability == 1)
			{
				if (svm_type == svm_parameter.EPSILON_SVR || svm_type == svm_parameter.NU_SVR)
				{
					System.Console.Out.Write("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma=" + svm.svm_get_svr_probability(model) + "\n");
				}
				else
				{
					svm.svm_get_labels(model, labels);
					prob_estimates = new double[nr_class];
					//UPGRADE_ISSUE: Method 'java.io.DataOutputStream.Write' was not converted. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1000_javaioDataOutputStreamWrite_javalangString"'
					output.Write("labels");
					for (int j = 0; j < nr_class; j++)
					{
						//UPGRADE_ISSUE: Method 'java.io.DataOutputStream.Write' was not converted. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1000_javaioDataOutputStreamWrite_javalangString"'
						output.Write(" " + labels[j]);
					}
					//UPGRADE_ISSUE: Method 'java.io.DataOutputStream.Write' was not converted. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1000_javaioDataOutputStreamWrite_javalangString"'
					output.Write("\n");
				}
			}
			while (true)
			{
				System.String line = input.ReadLine();
				if ((System.Object) line == null)
					break;
			
				SupportClass.Tokenizer st = new SupportClass.Tokenizer(line, " \t\n\r\f:");
			
				double target = atof(st.NextToken());
				int m = st.Count / 2;
				svm_node[] x = new svm_node[m];
				for (int j = 0; j < m; j++)
				{
					x[j] = new svm_node();
					x[j].index = atoi(st.NextToken());
					x[j].value_Renamed = atof(st.NextToken());
				}
			
				double v;
				if (predict_probability == 1 && (svm_type == svm_parameter.C_SVC || svm_type == svm_parameter.NU_SVC))
				{
					v = svm.svm_predict_probability(model, x, prob_estimates);
					output.Write(v + " ");
					for (int j = 0; j < nr_class; j++)
					{
						output.Write(prob_estimates[j] + " ");
					}
					output.Write("\n");
				}
				else
				{
					v = svm.svm_predict(model, x);
					output.Write(v + "\n");
				}
			
				if (v == target) ++correct;
				error += (v - target) * (v - target);
				sumv += v;
				sumy += target;
				sumvv += v * v;
				sumyy += target * target;
				sumvy += v * target;
				++total;
			}
			System.Console.Out.Write("Accuracy = " + (double) correct / total * 100 + "% (" + correct + "/" + total + ") (classification)\n");
			System.Console.Out.Write("Mean squared error = " + error / total + " (regression)\n");
			System.Console.Out.Write("Squared correlation coefficient = " + ((total * sumvy - sumv * sumy) * (total * sumvy - sumv * sumy)) / ((total * sumvv - sumv * sumv) * (total * sumyy - sumy * sumy)) + " (regression)\n");
		}

		/// <summary>
		/// Predict single vector the format of the vector is almost the same as in normal svm but withou class attribute in the beginning
		/// </summary>
		/// <param name="singleVector"></param>
		/// <param name="model"></param>
		/// <param name="predict_probability"></param>
		public double PredictSingleVector(string singleVector,svm_model model, int predict_probability)
		{
			int svm_type = svm.svm_get_svm_type(model);
			int nr_class = svm.svm_get_nr_class(model);
			int[] labels = new int[nr_class];
			double[] prob_estimates = null;

			if (predict_probability == 1)
			{
				if (svm_type == svm_parameter.EPSILON_SVR || svm_type == svm_parameter.NU_SVR)
				{
					System.Console.Out.Write("Prob. model for test data: target value = predicted value + z,\nz: Laplace distribution e^(-|z|/sigma)/(2sigma),sigma=" + svm.svm_get_svr_probability(model) + "\n");
				}
				else
				{
					svm.svm_get_labels(model, labels);
					prob_estimates = new double[nr_class];
				}
			}

			SupportClass.Tokenizer st = new SupportClass.Tokenizer(singleVector, " \t\n\r\f:");
			
			//skip class
			//st.NextToken();

			int m = st.Count / 2;
			svm_node[] x = new svm_node[m];
			for (int j = 0; j < m; j++)
			{
				x[j] = new svm_node();
				x[j].index = atoi(st.NextToken());
				x[j].value_Renamed = atof(st.NextToken());
			}
			
			double v;
			if (predict_probability == 1 && (svm_type == svm_parameter.C_SVC || svm_type == svm_parameter.NU_SVC))
			{
				v = svm.svm_predict_probability(model, x, prob_estimates);
			}
			else
			{
				v = svm.svm_predict(model, x);
			}
			
			return v;
		}
	
		public static void  exit_with_help()
		{
			System.Console.Error.Write("usage: svm_predict [options] test_file model_file output_file\n" + "options:\n" + "-b probability_estimates: whether to predict probability estimates, 0 or 1 (default 0); one-class SVM not supported yet\n");
			System.Environment.Exit(1);
		}
	
	}
}